<template>
  <div id="app">
    <input type="file" style="display:none;" id="file" />
    <el-button type="primary" @click="uploadFile">选择上传文件</el-button>
    <el-button type="warning" @click="confirmUpload">开始上传</el-button>
    <div class="progress">
      <span>上传进度：{{total|totalText}}%</span>
      <el-link type="primary" v-if="total>0 && total<100" @click="handleBtn">{{btn|btnText}}</el-link>
    </div>
  </div>
</template>

<script>
import axios from 'axios';
import SparkMD5 from "spark-md5";
export default {
  name: 'App',
  data () {
    return {
      currentFile: null,
      total: 0,
      btn: false,
    }
  },
  filters: {
    btnText (btn) {
      return btn ? "继续" : "暂停";
    },
    totalText (total) {
      return total > 100 ? 100 : total;
    },
  },
  methods: {
    // 点击上传按钮
    uploadFile () {
      const that = this;
      const fileNode = document.getElementById('file');
      fileNode.click();
      fileNode.addEventListener('change', function (ev) {
        that.currentFile = ev.target.files[0];
      })
    },
    // 上传前的钩子函数
    beforeUpload (file) {
      if (!file) {
        this.$message.warning('请选择上传的文件');
        return false;
      }
      const { type, size } = file;
      // 文件格式化校验
      if (!/(mp4|wmv)$/i.test(type)) {
        this.$message.warning("文件合适不正确");
        return false;
      }
      return true;
    },
    // 开始上传
    async confirmUpload () {
      let formData = new FormData();
      const currentFile = this.currentFile;
      // 上传前的钩子函数
      const flag = this.beforeUpload(currentFile);
      if (!flag) {
        return false;
      };
      const fileBuffer = await this.fileParse(currentFile, 'buffer');
      let spark = new SparkMD5.ArrayBuffer();
      spark.append(fileBuffer);
      const hash = spark.end();
      const suffix = /\.([0-9a-zA-Z]+)$/i.exec(currentFile.name)[1];
      // 将文件切割为100份来上传
      let partList = [];
      const partSize = currentFile.size / 100;
      let cur = 0;
      for (let i = 0; i < 100; i++) {
        let item = {
          chunk: currentFile.slice(cur, cur + partSize),
          filename: `${hash}_${i}.${suffix}`,
        }
        cur += partSize;
        partList.push(item);
      }
      this.partList = partList;
      this.hash = hash;
      // 发送ajax请求到服务器端
      this.sendRequest();
    },
    async sendRequest () {
      // 根据多少切片来创建多少请求
      let requestList = [];
      // 设置请求头
      const headers = {
        // "Content-Type": "multipart/form-data",
      }
      this.partList.forEach((item, index) => {
        const fn = () => {
          let formData = new FormData();
          formData.append('chunk', item.chunk);
          formData.append('filename', item.filename);
          // 发送ajax请求
          axios.post('/upload3', formData, { headers }).then(res => {
            const data = res.data;
            if (data.code == 0) {
              this.total += 1;
              // 传完的切片我们把它移除掉
              this.partList.splice(index, 1);
            }
          })
        }
        requestList.push(fn);
      });
      let currentIndex = 0;
      const send = async () => {
        // 如果中断上传就不在发送请求
        if (this.abort) return;
        if (currentIndex >= requestList.length) {
          // 调用上传完成的按钮,告诉后端合并文件
          this.complete();
          return;
        }
        await requestList[currentIndex]();
        currentIndex++;
        send();
      }
      send();
    },
    // 文件上传,需要后端合并文件
    complete () {
      axios.get('/merge', {
        params: {
          hash: this.hash,
        }
      }).then(res => {
        console.log(res, '上传完成');
      })
    },
    // 将文件转换为bs64
    fileParse (file, type = "base64") {
      return new Promise(resolve => {
        let fileRead = new FileReader();
        if (type === "base64") {
          fileRead.readAsDataURL(file);
        } else if (type === "buffer") {
          fileRead.readAsArrayBuffer(file);
        }
        fileRead.onload = (ev) => {
          resolve(ev.target.result);
        };
      });
    },
    // 暂停和开始
    handleBtn () {
      if (this.btn) {
        //断点续传
        this.abort = false;
        this.btn = false;
        this.sendRequest();
        return;
      }
      //暂停上传
      this.btn = true;
      this.abort = true;
    }
  },
  components: {
  }
}
</script>

<style lang="less">
</style>
